package com.qing.transfomer.util;

import com.alibaba.fastjson.JSONObject;
import com.qing.transfomer.dto.BaseListRequestDTO;
import com.qing.transfomer.dto.mapping.CodeMappingResultDTO;
import com.qing.transfomer.dto.mapping.QingFlowResponseDTO;
import com.qing.transfomer.dto.qing.*;
import lombok.SneakyThrows;
import org.springframework.beans.BeanUtils;
import org.springframework.util.CollectionUtils;

import java.lang.reflect.Field;
import java.util.*;

public class QingMappingUtil {

    /**
     * 将原始的BaseListRequestDTO对象转换为ApplyFilterRequestDTO对象
     *
     * @param listRequestDTO
     * @param codeMappingResult
     * @param <T>
     * @return
     */
    @SneakyThrows
    public static <T extends BaseListRequestDTO> ApplyFilterRequestDTO transferToApplyFilterRequest(T listRequestDTO, CodeMappingResultDTO codeMappingResult) {
        ApplyFilterRequestDTO applyFilterRequestDTO = new ApplyFilterRequestDTO();
        BeanUtils.copyProperties(listRequestDTO, applyFilterRequestDTO);
        List<ApplyFilterQuery> queries = new ArrayList<>();

        Map<String, String> mappings = invertMappings(codeMappingResult.getMappings());
        Class<? extends BaseListRequestDTO> aClass = listRequestDTO.getClass();
        Field[] declaredFields = aClass.getDeclaredFields();
        for (Field declaredField : declaredFields) {
            declaredField.setAccessible(true);
            String name = declaredField.getName();
            String queIdStr = mappings.get(name);
            if (Objects.isNull(queIdStr)) {
                continue;
            }

            ApplyFilterQuery applyFilterQuery = new ApplyFilterQuery();
            applyFilterQuery.setQueId(Integer.parseInt(queIdStr));

            Object fieldValue = declaredField.get(listRequestDTO);
            if (fieldValue instanceof List) {
                List<?> listValue = (List<?>) fieldValue;
                if (!listValue.isEmpty()) {
                    applyFilterQuery.setMinValue(listValue.get(0).toString());
                }
                if (listValue.size() > 1) {
                    applyFilterQuery.setMaxValue(listValue.get(1).toString());
                }
            } else {
                applyFilterQuery.setSearchKey(fieldValue.toString());
            }

            queries.add(applyFilterQuery);
        }
        applyFilterRequestDTO.setQueries(queries);

        return applyFilterRequestDTO;
    }

    /**
     * 反转映射中的键值对。
     * 该方法通过流式处理原始映射的条目集，然后收集以形成一个新的映射，
     * 将原始映射中的值作为新映射的键，将原始映射中的键作为新映射的值。
     *
     * @param <K>      原始映射中键的类型，在反转后的映射中作为值的类型
     * @param <V>      原始映射中值的类型，在反转后的映射中作为键的类型
     * @param mappings 包含要反转的键值对的原始映射对象
     * @return 返回包含反转后键值对的新映射
     */
    private static <K, V> Map<V, K> invertMappings(Map<K, V> mappings) {
        return mappings.entrySet().stream()
                .collect(HashMap::new, (m, e) -> m.put(e.getValue(), e.getKey()), HashMap::putAll);
    }

    /**
     * 将原始的QingFlowResponseDTO对象转换为List<JSONObject>对象
     *
     * @param qingFlowResponseDTO
     * @param codeMappingResult
     * @return
     */
    public static List<JSONObject> transferApplyFilterResponse(QingFlowResponseDTO<ApplyFilterResultDTO> qingFlowResponseDTO, CodeMappingResultDTO codeMappingResult) {
        List<JSONObject> result = new ArrayList<>();
        ApplyFilterResultDTO applyFilterResultDTO = qingFlowResponseDTO.getResult();
        if (Objects.isNull(applyFilterResultDTO)) {
            return result;
        }
        List<ApplyInfoDTO> applyInfoDTOS = applyFilterResultDTO.getResult();
        if (CollectionUtils.isEmpty(applyInfoDTOS)) {
            return result;
        }
        ApplyInfoDTO applyInfoDTO = applyInfoDTOS.get(0);
        List<ApplyAnswerDTO> answers = applyInfoDTO.getAnswers();
        if (CollectionUtils.isEmpty(answers)) {
            return result;
        }
        Map<String, String> mappings = codeMappingResult.getMappings();
        return answers.stream().map(answer -> {
            JSONObject jsonObject = new JSONObject();
            String queId = answer.getQueId().toString();
            ApplyAnswerValueDTO applyAnswerValueDTO = answer.getValues().get(0);

            jsonObject.put(mappings.get(queId), applyAnswerValueDTO.getValue());

            return jsonObject;
        }).toList();
    }
}